#pragma once

#include <vector>
#include <fstream>

#include "Utils.h"
#include "Tile.h"
#include "Sprites.h"
#include "GameDeviceSingleton.h"

using namespace std;

/*  
@description Get map tiles information from file 
*/

class TileManager {
private: 
	void _calculateWH() {
		this->tileWidth = mapTileIds->at(2);
		this->tileHeight = mapTileIds->at(3);
		this->width = mapTileIds->at(1) * tileWidth;
		this->height = mapTileIds->at(0) * tileHeight;
		mapTileIds->erase(mapTileIds->begin() + 0);
		mapTileIds->erase(mapTileIds->begin() + 0);
		mapTileIds->erase(mapTileIds->begin() + 0);
		mapTileIds->erase(mapTileIds->begin() + 0);
	}

	void _initSprites(int IdMapTile) {
		sprite = new Sprite(*(GameDeviceSingleton::getInstance()->getSpriteHandler()), IdMapTile , false);
	}

	void getMapTile(int gameLevel)
	{
		switch (gameLevel)
		{
		case GameLevel1:
			mapTileIds = GetMapTileIds(_FILE_MAP_TILE_1);
			_initSprites(_ID_MAP_STAGE1_BGR_TILES);
			break;
		case GameLevel1Sprite:
			mapTileIds = GetMapTileIds(_FILE_MAP_TILE_1_SPRITE);
			_initSprites(_ID_MAP_STAGE1_BGR_TILES_SPRITE);
			break;
		case GameLevel2Sprite:
			mapTileIds= GetMapTileIds(_FILE_MAP_TILE_2_SPRITE);
			_initSprites(_ID_MAP_STAGE2_BGR_TILES_SPRITE);
			break;
		case GameLevel2:
			mapTileIds = GetMapTileIds(_FILE_MAP_TILE_2);
			_initSprites(_ID_MAP_STAGE2_BGR_TILES);
			break;
		case GameLevel3:
			mapTileIds = GetMapTileIds(_FILE_MAP_TILE_3);
			_initSprites(_ID_MAP_STAGE3_BGR_TILES);
			break;
		case GameLevel3Sprite:
			mapTileIds = GetMapTileIds(_FILE_MAP_TILE_3);
			_initSprites(_ID_MAP_STAGE3_BGR_TILES_SPRITE);
			break;
		default:
			mapTileIds = GetMapTileIds(_FILE_MAP_TILE_1);
			_initSprites(_ID_MAP_STAGE1_BGR_TILES);
			break;
		}
	}

public:
	/* Contains bitmap id in map */
	vector<int>* mapTileIds;
	/* Contains tiles in map */
	vector<CTile>* mapTiles;
	/* Map width*/
	double width;
	/*Map height*/
	double height;
	int tileWidth;
	int tileHeight;
	/* Sprite to draw tiles map */
	Sprite* sprite; 
	CViewPort* viewport;

	TileManager(int mapLevel) {
		getMapTile(mapLevel);
		_calculateWH();
		mapTiles = GetMapTiles(this->width, this->height);

		viewport = GameDeviceSingleton::getInstance()->getViewPort();
	}

	void draw() {
		int index = 0;
		//Get map position in targetRect 
		int X = viewport->getX();
		int Y = viewport->getY();
		int startW = X - X % tileWidth;
		int startH = Y - Y % tileHeight;
		double maxHeight = 0;
		//
		if(this->height <= viewport->_data->Height)
		{
			maxHeight = this->height;
		}
		else
		{
			maxHeight = viewport ->getBottom() + 32;
		}
		//
		for(int i = startH; i <= maxHeight; i+= tileHeight)
		{
			for(int j = startW; j < viewport->getright() + 32; j+= tileWidth)
			{

				//Get index of bitmap from position
				index = ((this->height - i)/tileHeight) * (this->width/tileWidth) - 1 + j/tileWidth + 1;
				//Get bitmap from bitmap list to render
				if(index < mapTileIds->size())
				{
					sprite->setIndex(mapTiles->at(mapTileIds->at(index)).ID);
					sprite->Render(NULL, j + tileWidth/2, i - tileHeight/2);
				}
			}
		}
	}

	std::vector<int>* GetMapTileIds(LPWSTR FileName)
	{
		std::vector<int>* result = new vector<int>();
		ifstream file(FileName);
		string readingLine;
		int curPos = 0;
		int prevPos = 0;
		int spacePos = 0;
		int id;
		while(getline(file, readingLine))
		{
			//Add id from file to list
			curPos = 0;
			prevPos = 0;
			spacePos = 0;
			do
			{
				spacePos = readingLine.find(" ", curPos);

				if(spacePos >= 0)
				{
					curPos = spacePos;
					id = atoi(readingLine.substr(prevPos,curPos - prevPos).c_str());
					result->push_back(id);
					prevPos = ++curPos;
				}

			}while(spacePos >= 0);
			if(prevPos < readingLine.length())
			{
				id = atoi(readingLine.substr(prevPos,readingLine.length()).c_str());
				result->push_back(id);
			}

		}

		return result;
	}

	vector<CTile>* GetMapTiles(double MapWidth, double MapHeight)
	{
		vector<CTile>* result = new vector<CTile>();
		int index = 0;
		for(int i = 0; i < MapHeight; i+=tileHeight)
		{
			for(int j = 0; j < MapWidth; j += tileWidth)
			{
				CTile tile = CTile(result->size(),index++);
				result->push_back(tile);
			}
		}

		return result;
	}

	void changeTile(int gameLevel)
	{
		this->mapTileIds->clear();
		getMapTile(gameLevel);
		//this->mapTileIds = GetMapTileIds(filename);
		_calculateWH();
		mapTiles = GetMapTiles(this->width, this->height);
		//_initSprites(IdMapTile);
	}


};
